#pragma once

#include <iostream>
#include <cstdio>
#include <string>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
using namespace std;

string pathname = ".";
int proj_id = 0x66;
int defaultsize = 4096;

class SharedMemory
{
public:
    SharedMemory(int size = defaultsize)
        : _key(0), _size(size), _shmid(0), _start_addr(nullptr), windex(0), rindex(0)
    {
    }

    bool Create()
    {
        // 取得key值
        _key = ftok(pathname.c_str(), proj_id);
        if (_key < 0)
        {
            perror("ftok");
            return false;
        }

        _shmid = shmget(_key, _size, IPC_CREAT | IPC_EXCL | 0666);
        if (_shmid < 0)
        {
            perror("shmget");
            return false;
        }
        printf("共享内存创建成功：%d\n", _shmid);
        printf("_key: 0x%x\n", _key);

        return true;
    }

    bool Get()
    {
        // 取得key值
        _key = ftok(pathname.c_str(), proj_id);
        if (_key < 0)
        {
            perror("ftok");
            return false;
        }
        // 获取共享内存
        _shmid = shmget(_key, _size, IPC_CREAT);
        if (_shmid < 0)
        {
            perror("shmget");
            return false;
        }
        printf("共享内存获取成功：%d\n", _shmid);
        printf("_key: 0x%x\n", _key);

        return true;
    }

    bool Delete()
    {
        int n = shmctl(_shmid, IPC_RMID, nullptr);
        if (n < 0)
        {
            perror("shmctl");
            return false;
        }
        cout << "共享内存删除成功!" << endl;
        return 0;
    }

    bool Attch()
    {
        _start_addr = shmat(_shmid, nullptr, 0);
        if ((long long)_start_addr == -1)
        {
            perror("shmat");
            return false;
        }
        printf("成功将共享内存附加到虚拟地址空间中!\n");
        printf("_start_addr: %p\n", _start_addr);
        return true;
    }

    bool Detach()
    {
        int n = shmdt(_start_addr);
        if (n < 0)
        {
            perror("shmdt");
            return false;
        }
        cout << "成功将共享内存与虚拟地址空间进行去关联!" << endl;
        return true;
    }

    void Write(char ch)
    {

        ((char *)_start_addr)[windex++] = ch;
        ((char *)_start_addr)[windex] = '\0';
        // 避免越界
        windex %= _size;
        cout << "wirte: " << ch << endl;
        sleep(1);
    }

    void Read(char ch)
    {
        ch = ((char *)_start_addr)[rindex];
        // 和Write保持同步
        if (ch != '\0')
        {
            rindex++;
            rindex %= _size;
        }
        printf("server read: %c\n", ch);
        sleep(1);
    }

    void Print()
    {
        struct shmid_ds ds;
        int n = shmctl(_shmid, IPC_STAT, &ds);
        if (n < 0)
        {
            perror("shmctl");
            return;
        }

        printf("key: 0x%x\n", ds.shm_perm.__key);
        printf("size: %ld\n", ds.shm_segsz);
        printf("atime: %lu\n", ds.shm_atime);
        printf("nattach: %ld\n", ds.shm_nattch);
    }

    ~SharedMemory()
    {
    }

private:
    key_t _key;        // 键值
    int _size;         // 共享内存的大小
    int _shmid;        // 共享内存标识符
    void *_start_addr; // 共享内存在虚拟地址空间中的起始地址
    int windex;        // 写入数据的位置
    int rindex;        // 读取数据的位置
};
